package ar.com.age.distribuidora.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import ar.com.age.distribuidora.dao.CobroDao;
import ar.com.age.distribuidora.dao.FacturaVentaDao;
import ar.com.age.distribuidora.dao.LineaFacturaDao;
import ar.com.age.distribuidora.dominio.Cobro;
import ar.com.age.distribuidora.dominio.EntregaCheque;
import ar.com.age.distribuidora.dominio.EntregaEfectivo;
import ar.com.age.distribuidora.dominio.FacturaVenta;
import ar.com.age.distribuidora.dominio.LineaFactura;
import ar.com.age.distribuidora.service.EntregaService;
import ar.com.age.distribuidora.service.VentaService;

public class VentaServiceImpl implements VentaService {

	private CobroDao cobroDao;
	
	private LineaFacturaDao lineaFacturaDao;
	
	private FacturaVentaDao facturaVentaDao;
	
	private EntregaService entregaService;
	
	@Autowired(required = true)
	public void setCobroDao(CobroDao cobroDao) {
		this.cobroDao = cobroDao;
	}
    
    @Autowired(required = true)
	public void setLineaFacturaDao(LineaFacturaDao lineaFacturaDao) {
		this.lineaFacturaDao = lineaFacturaDao;
	}
    
    @Autowired(required = true)
	public void setEntregaService(EntregaService entregaService) {
		this.entregaService = entregaService;
	}
    
    @Autowired(required = true)
	public void setFacturaVentaDao(FacturaVentaDao facturaVentaDao) {
		this.facturaVentaDao = facturaVentaDao;
	}
    
    // Cobro
    @Override
	public void crearOEditarCobro(Cobro cobro) {
		
    	// actualizar el MontoActual de la entrega 
    	if (cobro.getEntrega().getClass().equals(EntregaEfectivo.class)) {

    		cobro.getEntrega().setMontoActual(cobro.getEntrega().getMontoActual() - cobro.getMonto());
    		entregaService.crearOEditarEntregaEfectivo((EntregaEfectivo) cobro.getEntrega());

    		cobroDao.saveOrUpdate(cobro);		

    	} else {

    		cobro.getEntrega().setMontoActual(cobro.getEntrega().getMontoActual() - cobro.getMonto());
    		entregaService.crearOEditarEntregaCheque((EntregaCheque) cobro.getEntrega());

    		cobroDao.saveOrUpdate(cobro);

    	}
    	//cobroDao.saveOrUpdate(cobro);		
    }

	@Override
	public List<Cobro> buscarTodosCobro() {

		return cobroDao.getAll();
	}
	
	@Override
	public void eliminarCobro(Cobro cobro) {
		
    	// actualizar el MontoActual de la entrega 
		if (cobro.getEntrega().getClass().equals(EntregaEfectivo.class)) {

    		cobro.getEntrega().setMontoActual(cobro.getEntrega().getMontoActual() + cobro.getMonto());
    		entregaService.crearOEditarEntregaEfectivo((EntregaEfectivo) cobro.getEntrega());

    		cobroDao.physicalDelete(cobro);		

    	} else {

    		cobro.getEntrega().setMontoActual(cobro.getEntrega().getMontoActual() + cobro.getMonto());
    		entregaService.crearOEditarEntregaCheque((EntregaCheque) cobro.getEntrega());

    		cobroDao.physicalDelete(cobro);

    	}
		
		
		//cobroDao.physicalDelete(cobro);
	}
	
	@Override
	public List<Cobro> buscarCobro(String codigo, String estado, Date desde, Date hasta) {

		return cobroDao.find(codigo, estado, desde, hasta);
	}
	
	//Linea Factura
	@Override
	public void crearOEditarLineaFactura(LineaFactura lineaFactura) {
		
		// Antes de guardar la linea se calcula la ganancia para esa linea...
		lineaFacturaDao.saveOrUpdate(lineaFactura);		
	}

	@Override
	public List<LineaFactura> buscarTodosLineaFactura() {

		return lineaFacturaDao.getAll();
	}
	
	@Override
	public void eliminarLineaFactura(LineaFactura lineaFactura) {
		
		lineaFacturaDao.physicalDelete(lineaFactura);		
	}
	
	//Factura Venta
	@Override
	public void crearOEditarFacturaVenta(FacturaVenta facturaVenta) {

		// Antes de guardar la factura se calcula la ganancia total de la venta...

		Double ganancia = new Double(0.0);
		for(LineaFactura linea : facturaVenta.getLineasFactura()){

			ganancia = ganancia + linea.getGanancia();
		}

		facturaVenta.setGanancia(ganancia);

		facturaVentaDao.saveOrUpdate(facturaVenta);		
	}

	@Override
	public List<FacturaVenta> buscarTodosFacturaVenta() {

		return facturaVentaDao.getAll();
	}
	
	@Override
	public void eliminarFacturaVenta(FacturaVenta facturaVenta) {
		
		facturaVentaDao.physicalDelete(facturaVenta);
	}
	
	@Override
	public List<FacturaVenta> buscarFacturaVenta(String estado, String codigo, String tipo, Date desde, Date hasta) {

		List<FacturaVenta> facturas = facturaVentaDao.find(estado, codigo, tipo, desde, hasta);
		List<FacturaVenta> facturasCompletas = new ArrayList<FacturaVenta>();
		
		for(FacturaVenta fv : facturas){
			
			facturasCompletas.add(this.getFacturaVentaConListas(fv));
		}
		
		return facturasCompletas;
	}
	
	@Override
	public Double retornarSaldoAdeudado(FacturaVenta facturaVenta){
		
		// Retorna lo que falta cobrar de la factura
		// saldoCobrado va a ser la suma de todos los cobros
		Double saldoCobrado = new Double(0.0);
		for(Cobro cobro : facturaVenta.getCobros()){
			
			saldoCobrado = saldoCobrado + cobro.getMonto();
		}
		
		// Retorno la resta del saldo total a cobrar de la factura menos todo lo que ya se cobro
		return facturaVenta.getSaldo() - saldoCobrado;
	}
	
	@Override
	public void agregarCobroAFacturaVenta(FacturaVenta facturaVenta, Cobro cobro) {
		
		// Registro el nuevo cobro
		this.crearOEditarCobro(cobro);
		
		// Lo agrego a la lista de cobros de la factura
		facturaVenta.agregarCobro(cobro);
		
		// Calculo si ya se saldo la factura para cambiar el estado
		if(this.retornarSaldoAdeudado(facturaVenta) == 0.0){
			
			facturaVenta.setEstado("Pagada");
		}
		
		// Actualizo la factura
		this.crearOEditarFacturaVenta(facturaVenta);
	}
	
	@Override
	public void agregarLineaFacturaAFacturaVenta(FacturaVenta facturaVenta, LineaFactura lineaFactura) {
		
		// Registro la nueva Linea en una Factura ya registrada en la BD
		this.crearOEditarLineaFactura(lineaFactura);
		
		// Lo agrego a la lista de lineas de la factura
		facturaVenta.agregarLineaFactura(lineaFactura);
		
		// Actualizo el saldo de la factura
		facturaVenta.setSaldo(facturaVenta.getSaldo() + (lineaFactura.getCantidad() * lineaFactura.getPrecio()));
		
		// Actualizo la Ganancia total en la factura
		Double aux = new Double(0.0);
		aux = facturaVenta.getGanancia() + lineaFactura.getGanancia();
		facturaVenta.setGanancia(aux);
		
		// Actualizo la factura
		this.crearOEditarFacturaVenta(facturaVenta);
	}
	
	@Override
	public FacturaVenta retornarFacturaVentaConCobros(FacturaVenta factura) {
		
		return facturaVentaDao.getFacturaVentaConCobros(factura);
	}
	
	@Override
	public FacturaVenta retornarFacturaVentaConLineas(FacturaVenta factura) {
		
		return facturaVentaDao.getFacturaVentaConLineas(factura);
	}
	
	@Override
	public FacturaVenta getFacturaVentaConListas(FacturaVenta factura) {

		return facturaVentaDao.getFacturaVentaConListas(factura);
	}

	// Informes
	@Override
	public List<FacturaVenta> getFacturasInformes(String producto, String cliente, String tipoCliente, Date desde, Date hasta) {

		List<FacturaVenta> facturas = facturaVentaDao.getFacturasInformes(cliente, tipoCliente, desde, hasta);
		List<FacturaVenta> facturasConListas = new ArrayList<FacturaVenta>(); 
		List<FacturaVenta> facturasInformes = new ArrayList<FacturaVenta>();

		for(FacturaVenta f : facturas) {
			facturasConListas.add(facturaVentaDao.getFacturaVentaConListas(f));
		}

		// Filitrar por Productos
		if(producto != "") {

			for(FacturaVenta f : facturasConListas) {

				// Recorro la lista de Lineas de Factura
				for(LineaFactura linea : f.getLineasFactura()) {

					if(linea.getLoteDeCompra().getProducto().getCodigo().equals(producto)) {

						facturasInformes.add(f);
						break;
					}
				}
			}
		}
		else {
			// Todas las facturas
			facturasInformes = facturasConListas;
		}

		return facturasInformes;
	}
}
